/**
 * @fileoverview
 * TODO doc me
 */


// Shortcuts
var log = YAHOO.log;
var assert = YAHOO.util.Assert;


// ************************************************************
// MODULE TESTS
// ************************************************************


/**
 * TODO declare the class
 */
flyui.flyted.Service.ModuleTests = function(){};


/** 
 * Test that the contents of the flyui.flyted.Service module have been defined.
 */
flyui.flyted.Service.ModuleTests.testModuleContents = function() {
	
	log("Test \"==== flyui.flyted.Service ModuleTests :: testModuleContents ====\" started.");
	
	assert.isNotUndefined(flyui.flyted.Service, "flyui.flyted.Service is undefined");	
	
	assert.isNotUndefined(flyui.flyted.Image, "flyui.flyted.Image is undefined");
	
};


/**
 * TODO
 */
flyui.flyted.Service.ModuleTestCase = function (){
	var testCase = new YAHOO.tool.TestCase({
		
		name: "=== flyui.flyted.Service ModuleTests ===",
		
		testModuleContents : flyui.flyted.Service.ModuleTests.testModuleContents
		
	});
	
	return testCase;
}


// ************************************************************
// SERVICE TESTS
// ************************************************************


/**
 * TODO
 */
flyui.flyted.Service.ServiceTests = function(){};


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testQuery = function(endpointURL, testCase){
	log("Test \"==== flyui.flyted.Service ServiceTests :: testQuery ====\" started.");
		
	var service = new flyui.flyted.Service(endpointURL);
	var query = "ASK { ?s ?p ?o }";
	
	var testOnSuccess = function(responseObject) {
		log("resume test case (success)", "test");
		testCase.resume(function() {
			
			// check status code			
			assert.areEqual(200, responseObject.status);
			
			// try parsing response text as json
			var resultSet = YAHOO.lang.JSON.parse(responseObject.responseText);
			
			// check json content
			assert.isTrue(resultSet["boolean"], "result set not as expected");
		});
	};
	
	var testOnFailure = function(responseObject) {
		log("resume test case (failure)", "test");
		testCase.resume(function() {
			// force failure
			assert.fail("request failed, status "+responseObject.status + " " +responseObject.statusText);
		});
	};
	
	log("initiate request", "test");
	service.query(query, testOnSuccess, testOnFailure);
	
	log("suspend test case (if test runner hangs here, something is wrong)", "test");
	testCase.wait();
};


/**
 * TODO doc me
 * @static
 * @asynchronous
 */
flyui.flyted.Service.ServiceTests.testFindImagesByFlytedGeneName = function( geneName, expectedImages, endpointURL, testCase ) {
	
	log("Test \"==== flyui.flyted.Service ServiceTests :: testFindImagesByFlytedGeneName ("+geneName+") ====\" started.");
	
	var service = new flyui.flyted.Service(endpointURL);
	
	var testOnSuccess = function( images ) {
		log("resume test case (success)", "test");
		testCase.resume(function() {

			flyui.flyted.Service.TestData.compareImageArrays(expectedImages, images);
			
		});
	};

	var testOnFailure = function( response ) {
		log("resume test case (failure)", "test");
		testCase.resume(function() {
			assert.fail("request failed, "+response.status+" "+response.statusText);			
		});
	};

	log("initiate request", "test");
	service.findImagesByFlytedGeneName(geneName, testOnSuccess, testOnFailure);
	
	log("suspend test case (if test runner hangs here, something is wrong)", "test");
	testCase.wait();
	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_oneMapping = function( testCase, endpointURL ) {

	log("Test \"==== flyui.flyted.Service ServiceTests :: testFindImagesByFlybaseGeneID_oneMapping ====\" started.");

	var flybaseID = "FBgn0033960"; // maps to/from "CG10151" // N.B. need something that maps to a single flyted gene name
	var service = new flyui.flyted.Service(endpointURL);
	var testData = new flyui.flyted.Service.TestData();
	var expectedImages = [testData.CG10151_in_wt, testData.CG10151_in_comr_and_wt];
	
	var testOnSuccess = function( images ) {
		log("resume test case (success)", "test");
		testCase.resume(function() {
	
			flyui.flyted.Service.TestData.compareImageArrays(expectedImages, images);
		
		});
	};

	var testOnFailure = function( response ) {
		log("resume test case (failure)", "test");
		testCase.resume(function() {
			assert.fail("request failed, "+response.status+" "+response.statusText);			
		});
	};

	log("initiate request", "test");
	service.findImagesByFlybaseGeneID(flybaseID, testOnSuccess, testOnFailure);
	
	log("suspend test case (if test runner hangs here, something is wrong)", "test");
	testCase.wait();

}


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_twoMappings = function( testCase, endpointURL ) {

	log("Test \"==== flyui.flyted.Service ServiceTests :: testFindImagesByFlybaseGeneID_twoMappings ====\" started.");

	// N.B. need something that maps to two flyted gene names
	var flybaseID = "FBgn0052548"; // "FBgn0052548":["CG32548","CG6306"] 

	var service = new flyui.flyted.Service(endpointURL);

	var testOnSuccess = function( images ) {
		log("resume test case (success)", "test");
		testCase.resume(function() {
	
			assert.areEqual(4, images.length, "expect 4 images");
		
		});
	};

	var testOnFailure = function( response ) {
		log("resume test case (failure)", "test");
		testCase.resume(function() {
			assert.fail("request failed, "+response.status+" "+response.statusText);			
		});
	};

	log("initiate request", "test");
	service.findImagesByFlybaseGeneID(flybaseID, testOnSuccess, testOnFailure);
	
	log("suspend test case (if test runner hangs here, something is wrong)", "test");
	testCase.wait();

}

/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_noMapping = function( testCase, endpointURL ) {

	log("Test \"==== flyui.flyted.Service ServiceTests :: testFindImagesByFlybaseGeneID_noMapping ====\" started.");

	var flybaseID = "this has no mapping"; 
	var service = new flyui.flyted.Service(endpointURL);

	var testOnSuccess = function( images ) {
		assert.areEqual(0, images.length, "expect empty array of images if no mapping");	
	};

	var testOnFailure = function( response ) {
		assert.fail("this should never be called as request is processed synchronously");			
	};

	log("initiate request", "test");
	service.findImagesByFlybaseGeneID(flybaseID, testOnSuccess, testOnFailure);

	// N.B. this is not asynchronous as expect service to respond immediately if no mappings are available	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_noResult = function() {
	
	var flytedNames = flyui.flyted.Service.mapFlybaseIDToFlytedGeneName("FBgn0001232");
	assert.areEqual(0, flytedNames.length);
	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_oneResult = function() {

	var flytedNames = flyui.flyted.Service.mapFlybaseIDToFlytedGeneName("FBgn0001233");
	assert.areEqual(1, flytedNames.length);
	assert.areEqual("Hsp83", flytedNames[0]);

}


/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_twoResults = function() {

	var flytedNames = flyui.flyted.Service.mapFlybaseIDToFlytedGeneName("FBgn0001234");
	assert.areEqual(2, flytedNames.length);
	var expected = ["Hsr-omega","hsr-omega"];
	assert.isTrue(flyui.util.arrayMembersAreEqual(expected, flytedNames), "name array comparison failed");

}

/**
 * Test gene name not used in FlyTED database
 */
flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_notUsed = function() {
	
	var flybaseIDs = flyui.flyted.Service.mapFlytedGeneNameToFlybaseID("CG3307");
	assert.areEqual(0, flybaseIDs.length);
	
}

/**
 * Test gene name used in FlyTED database, for which no Flybase ID mapping exists
 */
flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_noResult = function() {
	
	var flybaseIDs = flyui.flyted.Service.mapFlytedGeneNameToFlybaseID("alh");
	assert.areEqual(0, flybaseIDs.length);
	
}

/**
  * Test FlyTED name to Flybase ID mapping with one result expected
  */
flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_oneResult = function() {

	var flybaseIDs = flyui.flyted.Service.mapFlytedGeneNameToFlybaseID("CG3308");
	assert.areEqual(1, flybaseIDs.length);
	assert.areEqual("FBgn0038877", flybaseIDs[0]);

}


/**
  * Test FlyTED name to Flybase ID mapping with two results expected
 */
flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_twoResults = function() {

	var flybaseIDs = flyui.flyted.Service.mapFlytedGeneNameToFlybaseID("sdt");
	assert.areEqual(2, flybaseIDs.length);
	var expected = ["FBgn0002638","FBgn0243505"];
	assert.isTrue(flyui.util.arrayMembersAreEqual(expected, flybaseIDs), "name array comparison failed");

}

/**
 * TODO doc me
 */
flyui.flyted.Service.ServiceTestCase = function (endpointURL){
	var testCase = new YAHOO.tool.TestCase({
		name: "=== flyui.flyted.Service ServiceTests ===",
		
		testQuery : function() {
			flyui.flyted.Service.ServiceTests.testQuery(endpointURL, this);
		},
		
		testFindImagesByFlytedGeneName_foo : function() {
			var geneName = "foo";
			var testData = new flyui.flyted.Service.TestData();
			var expectedImages = [];
			flyui.flyted.Service.ServiceTests.testFindImagesByFlytedGeneName(geneName, expectedImages, endpointURL, this);
		},

		testFindImagesByFlytedGeneName_CG10998 : function() {
			var geneName = "CG10998";
			var testData = new flyui.flyted.Service.TestData();
			var expectedImages = [testData.CG10998_in_wt];
			flyui.flyted.Service.ServiceTests.testFindImagesByFlytedGeneName(geneName, expectedImages, endpointURL, this);
		},
		
		testFindImagesByFlytedGeneName_acer : function() {
			var geneName = "acer";
			var testData = new flyui.flyted.Service.TestData();
			var expectedImages = [testData.acer_in_aly, testData.acer_in_wt];
			flyui.flyted.Service.ServiceTests.testFindImagesByFlytedGeneName(geneName, expectedImages, endpointURL, this);
		}, 
		
		testMapFlybaseIDToFlytedGeneName_noResult : function() {
			flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_noResult();
		},
		
		testMapFlybaseIDToFlytedGeneName_oneResult : function() {
			flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_oneResult();
		},
		
		testMapFlybaseIDToFlytedGeneName_twoResults : function() {
			flyui.flyted.Service.ServiceTests.testMapFlybaseIDToFlytedGeneName_twoResults();
		},
		
		testMapFlytedGeneNameToFlybaseID_notUsed : function() {
			flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_notUsed();
		},
		
		testMapFlytedGeneNameToFlybaseID_noResult : function() {
			flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_noResult();
		},
		
		testMapFlytedGeneNameToFlybaseID_oneResult : function() {
			flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_oneResult();
		},
		
		testMapFlytedGeneNameToFlybaseID_twoResults : function() {
			flyui.flyted.Service.ServiceTests.testMapFlytedGeneNameToFlybaseID_twoResults();
		},
		
		testFindImagesByFlybaseGeneID_noMapping : function() {
			flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_noMapping(this, endpointURL);
		},

		testFindImagesByFlybaseGeneID_oneMapping : function() {
			flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_oneMapping(this, endpointURL);
		},

		testFindImagesByFlybaseGeneID_twoMappings : function() {
			flyui.flyted.Service.ServiceTests.testFindImagesByFlybaseGeneID_twoMappings(this, endpointURL);
		}
		
	});
	return testCase;
};


// ************************************************************
// IMAGE TESTS
// ************************************************************


/**
 * @class
 * A collection of tests to test the Image class.
 */
flyui.flyted.Service.ImageTests = function() {};


/**
 * TODO doc me
 */
flyui.flyted.Service.ImageTests.testNewImageFromSPARQLResults = function(){
	
	var testData = new flyui.flyted.Service.TestData();
	
	var images = flyui.flyted.Image.newInstancesFromSPARQLResults(testData.resultSet_CG10998);
	
	assert.areEqual(1, images.length, "one image expected");
	
	var image = images[0];
	
	flyui.flyted.Service.TestData.compareImages(testData.CG10998_in_wt, image);
	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ImageTests.testNewImagesFromSPARQLResults = function() {

	var testData = new flyui.flyted.Service.TestData();
	
	var images = flyui.flyted.Image.newInstancesFromSPARQLResults(testData.resultSet_acer);
	
	assert.areEqual(2, images.length, "two image expected");
	
	flyui.flyted.Service.TestData.compareImages(testData.acer_in_aly, images[0]);
	flyui.flyted.Service.TestData.compareImages(testData.acer_in_wt, images[1]);
	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ImageTests.testNewImagesFromEmptySPARQLResults = function() {

	var testData = new flyui.flyted.Service.TestData();
	
	var images = flyui.flyted.Image.newInstancesFromSPARQLResults(testData.resultSet_foo);
	
	assert.areEqual(0, images.length, "no images expected");
}


/**
 * TODO doc me
 */
flyui.flyted.Service.ImageTestCase = function (){
	var testCase = new YAHOO.tool.TestCase({
		name: "=== flyui.flyted.Service ImageTests ===",
		
		testNewImageFromSPARQLResults :  flyui.flyted.Service.ImageTests.testNewImageFromSPARQLResults,
		
		testNewImagesFromSPARQLResults : flyui.flyted.Service.ImageTests.testNewImagesFromSPARQLResults, 
		
		testNewImagesFromEmptySPARQLResults : flyui.flyted.Service.ImageTests.testNewImagesFromEmptySPARQLResults
		
	});
	return testCase;
}


// ************************************************************
// TEST DATA
// ************************************************************


/**
 * TODO doc me
 */
flyui.flyted.Service.TestData = function(){
	
	this.CG10151_in_wt = new flyui.flyted.Image();
	this.CG10151_in_wt.fullImageURL = "http://www.fly-ted.org/768/2/wt01.bmp";
	this.CG10151_in_wt.thumbnailURL = "http://www.fly-ted.org/768/thumbnails/2/medium.jpg";
	this.CG10151_in_wt.flytedURL = "http://www.fly-ted.org/768/";
	this.CG10151_in_wt.caption = "CG10151 in wt";
	this.CG10151_in_wt.geneName = "CG10151";

	this.CG10151_in_comr_and_wt = new flyui.flyted.Image();
	this.CG10151_in_comr_and_wt.fullImageURL = "http://www.fly-ted.org/769/2/wtandcomr.bmp";
	this.CG10151_in_comr_and_wt.thumbnailURL = "http://www.fly-ted.org/769/thumbnails/2/medium.jpg";
	this.CG10151_in_comr_and_wt.flytedURL = "http://www.fly-ted.org/769/";
	this.CG10151_in_comr_and_wt.caption = "CG10151 in comr AND wt";
	this.CG10151_in_comr_and_wt.geneName = "CG10151";
	
	this.CG10998_in_wt = new flyui.flyted.Image();
	this.CG10998_in_wt.fullImageURL = "http://www.fly-ted.org/742/2/wt01.bmp";
	this.CG10998_in_wt.thumbnailURL = "http://www.fly-ted.org/742/thumbnails/2/medium.jpg";
	this.CG10998_in_wt.flytedURL = "http://www.fly-ted.org/742/";
	this.CG10998_in_wt.caption = "CG10998 in wt";
	this.CG10998_in_wt.geneName = "CG10998";
		
	this.resultSet_CG10998 = {
	  "head": {
	    "vars": [ "fullImageURL" , "thumbnailURL" , "flytedURL" , "caption", "geneName" ]
	  } ,
	  "results": {
	    "bindings": [
	      {
	        "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/742/2/wt01.bmp" } ,
	        "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/742/thumbnails/2/medium.jpg" } ,
	        "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/742/" } ,
	        "caption": { "type": "literal" , "value": "CG10998 in wt" },
	        "geneName": { "type": "literal" , "value": "CG10998" }
	      }
	    ]
	  }
	};
	
	this.resultSet_acer = {
	  "head": {
	    "vars": [ "fullImageURL" , "thumbnailURL" , "flytedURL" , "caption", "geneName" ]
	  } ,
	  "results": {
	    "bindings": [
	      {
	        "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/1530/2/acer-aly.jpg" } ,
	        "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/1530/thumbnails/2/medium.jpg" } ,
	        "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/1530/" } ,
	        "caption": { "type": "literal" , "value": "acer in aly" },
	        "geneName": { "type": "literal" , "value": "acer" }
	      } ,
	      {
	        "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/1531/2/acer-wt.jpg" } ,
	        "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/1531/thumbnails/2/medium.jpg" } ,
	        "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/1531/" } ,
	        "caption": { "type": "literal" , "value": "acer in wt" },
	        "geneName": { "type": "literal" , "value": "acer" }
	      }
	    ]
	  }
	};
	
	this.acer_in_aly = new flyui.flyted.Image();
	this.acer_in_aly.fullImageURL = "http://www.fly-ted.org/1530/2/acer-aly.jpg";
	this.acer_in_aly.thumbnailURL = "http://www.fly-ted.org/1530/thumbnails/2/medium.jpg";
	this.acer_in_aly.flytedURL = "http://www.fly-ted.org/1530/";
	this.acer_in_aly.caption = "acer in aly";
	this.acer_in_aly.geneName = "acer";
	
	this.acer_in_wt = new flyui.flyted.Image();
	this.acer_in_wt.fullImageURL = "http://www.fly-ted.org/1531/2/acer-wt.jpg";
	this.acer_in_wt.thumbnailURL = "http://www.fly-ted.org/1531/thumbnails/2/medium.jpg";
	this.acer_in_wt.flytedURL = "http://www.fly-ted.org/1531/";
	this.acer_in_wt.caption = "acer in wt";
	this.acer_in_wt.geneName = "acer";
	
	this.resultSet_foo = {
	  "head": {
	    "vars": [ "fullImageURL" , "thumbnailURL" , "flytedURL" , "caption" ]
	  } ,
	  "results": {
	    "bindings": [
	      
	    ]
	  }
	};
}


/**
 * Compare two image objects.
 * @param {flyui.flyted.Image} expected
 * @param {flyui.flyted.Image} actual
 */
flyui.flyted.Service.TestData.compareImages = function( expected, actual ) {
	log("test flyted full image url", "test");
	assert.areEqual(expected.fullImageURL, actual.fullImageURL, "full image URL not expected");
	
	log("test flyted thumbnail url", "test");
	assert.areEqual(expected.thumbnailURL, actual.thumbnailURL, "thumbnail URL not expected");
	
	log("test url to flyted repository", "test");
	assert.areEqual(expected.flytedURL, actual.flytedURL, "FlyTED URL not expected");
	
	log("test image caption", "test");
	assert.areEqual(expected.caption, actual.caption, "image caption not expected");

	log("test image gene name", "test");
	assert.areEqual(expected.geneName, actual.geneName, "image gene name not expected");
	
}


/**
 * TODO doc me
 */
flyui.flyted.Service.TestData.compareImageArrays = function( expecteds, actuals ) {

	log("comparing image arrays", "test");

	assert.areEqual(expecteds.length, actuals.length, "number of images not as expected");
	
	var n = actuals.length;
	for (var i=0; i<n; i++) {
		var expected = expecteds[i];
		var found = false;
		for (var j=0; j<n; j++) {
			var image = actuals[j];
			if (image.fullImageURL == expected.fullImageURL) {
				found = true;
				flyui.flyted.Service.TestData.compareImages(expected, image);
			}
		}
		assert.isTrue(found, "did not find expected image "+expected.fullImageURL);
	}
	
}


// ************************************************************
// TEST SUITE AND RUNNER
// ************************************************************


/** 
 * Construct a YUI test suite for the flyui.flyted.Service module.
 * @param {String} endpointURL URL of service
 * @return a YUI test suite
 * @type YAHOO.tool.TestSuite
 */
flyui.flyted.Service.TestSuite = function(endpointURL) {
	var suite = new YAHOO.tool.TestSuite("== flyui.flyted.Service Test Suite ==");
	suite.add(flyui.flyted.Service.ModuleTestCase());
	suite.add(flyui.flyted.Service.ImageTestCase());
	suite.add(flyui.flyted.Service.ServiceTestCase(endpointURL));
	return suite;
}


/** 
 * Run the flyui.flyted.Service test suite.
 * @param {String} endpointURL URL of service
 */
flyui.flyted.Service.runTests = function(endpointURL) {
	YAHOO.log("flyui.flyted.Service :: running tests", "test");
	YAHOO.tool.TestRunner.add(flyui.flyted.Service.TestSuite(endpointURL));
	YAHOO.tool.TestRunner.run();
}
